package cn.admin.remoting.impl;


import cn.admin.remoting.*;
import cn.admin.remoting.util.ConnectionUrl;
import org.apache.mina.common.ConnectFuture;
import org.apache.mina.common.ThreadModel;
import org.apache.mina.transport.socket.nio.SocketConnector;
import org.apache.mina.transport.socket.nio.SocketConnectorConfig;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;

class ClientConnectionFactory extends DefaultConnectionFactory {

    private final String appName;
    private final SocketConnector connector;

    ClientConnectionFactory(String appName) {
        this.appName = appName;
        this.addListener(new LCL_negotiateIdleTimeout());
        this.addListener(new LCL_onClose4Reconnect());
        this.connector = new SocketConnector(processorCount,IO_THREAD_POOL);
    }

    Client createClient(String targetUrl, InetSocketAddress localAddress,
                        List<IOEventListener> ioListeners) throws RemotingException,
            InterruptedException {
        return this.createClientAsync(targetUrl,localAddress,ioListeners).get(-1L);
    }

    ClientManager.ClientFuture createClientAsync(String targetUrl,List<IOEventListener> ioListeners) {
        return this.createClientAsync(targetUrl,null,ioListeners);
    }

    ClientManager.ClientFuture createClientAsync(String targetUrl,InetSocketAddress localAddress,
                                                 List<IOEventListener> ioListeners) {
        String clientKey = ClientKeyUtil.singleClientKey(this.appName,targetUrl,localAddress);
        ArrayList<IOEventListener> copyListeners = new ArrayList<>();
        if (ioListeners != null) {
            copyListeners.addAll(ioListeners);
        }

        SocketConnectorConfig cfg = new SocketConnectorConfig();
        cfg.setThreadModel(ThreadModel.MANUAL);
        long timeoutMs = Math.max(ConnectionUrl.getConnectTimeout(targetUrl),1000L);
        long timeoutSeconds = timeoutMs / 1000L;
        cfg.setConnectTimeout(timeoutSeconds > 2147483647L ? 2147483647 : (int)timeoutSeconds);
        cfg.getSessionConfig().setTcpNoDelay(true);
        cfg.getFilterChain().addLast(CODEC_FILTER_NAME,CODEC_FILTER);
        ConnectFuture minaConnectFuture =
                this.connector.connect(ConnectionUrl.socketAddr(targetUrl),localAddress,
                        new DefaultIoHandler.ClientIoHandler(this,clientKey,copyListeners),
                        cfg);
        return new ClientFutureImpl(targetUrl,minaConnectFuture);
    }

    void closeAllClients() {
        for (Connection connection : this.allConnectionSnapshot()) {
            connection.close("测试专用，关闭该工厂的所有连接");
        }
    }

}
